<?php

declare(strict_types=1);
namespace App\Service;

use Doctrine\Common\Annotations\AnnotationReader;
use Hyperf\Apidog\Annotation\ApiController;
use Hyperf\Di\Annotation\AnnotationCollector;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Di\ReflectionManager;
use Hyperf\HttpServer\Annotation\Mapping;
use Hyperf\HttpServer\Router\DispatcherFactory;
use Hyperf\HttpServer\Router\Handler;
use Psr\Container\ContainerInterface;

class AdminLogs
{
    /**
     * @Inject()
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @return array
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public static function modules(): array
    {
        $data = [];
        $routerData = (new static())->container->get(DispatcherFactory::class)->getRouter('backend-api')->getData();
        array_walk_recursive($routerData, function ($router) use (&$data) {
            if ($router instanceof Handler && ! ($router->callback instanceof \Closure)) {
                [$module, $function] = self::prepareMoudleFunction($router->callback);
                if (!isset($data[$module])) {
                    $data[$module] = [
                        'module' => $module,
                        'functions' => [],
                    ];
                }
                $data[$module]['functions'][] = $function;
            }
        });
        /*$data = array_values($data);
        $collator = collator_create('zh-CN');
        usort($data, [$collator, 'compare']);*/
        return array_values($data);
    }

    /**
     * @param $callback
     * @return array
     * @throws \Doctrine\Common\Annotations\AnnotationException
     */
    public static function prepareMoudleFunction($callback): array
    {
        [$class, $method] = self::prepareClassMethod($callback);
        $module = $function = '';
        $classAnnotation = AnnotationCollector::list()[$class]['_c'] ?? [];
        if ($classAnnotation && ($controlerAnnotation = $classAnnotation[ApiController::class] ?? null)) {
            $module = $controlerAnnotation->tag;

            $reflectMethod = ReflectionManager::reflectMethod($class, $method);
            $reader = new AnnotationReader();
            foreach ($reader->getMethodAnnotations($reflectMethod) as $methodAnnotation) {
                if ($methodAnnotation instanceof Mapping) {
                    $mapping = $methodAnnotation;
                    $function = $mapping->description;
                    break;
                }
            }
        }
        return [$module ?: $class, $function ?: $method];
    }

    /**
     * @param $handler
     * @return array
     */
    public static function prepareClassMethod($handler): array
    {
        if (is_string($handler)) {
            if (strpos($handler, '@') !== false) {
                return explode('@', $handler);
            }
            return explode('::', $handler);
        }
        if (is_array($handler) && isset($handler[0], $handler[1])) {
            return $handler;
        }
        throw new \RuntimeException('Handler not exist.');
    }
}
